package com.training.service;

import com.training.entity.Class; // Import Class entity
import com.training.entity.Student; // Import Student entity
import com.training.entity.Course; // Import Course entity
import com.training.entity.ClassStudent; // Import ClassStudent entity
import com.training.entity.CouClass; // Import CouClass entity
import com.training.mapper.ClassMapper; // Import ClassMapper interface
import com.training.mapper.ClassStudentMapper; // Import ClassStudentMapper interface
import com.training.mapper.CouClassMapper; // Import CouClassMapper interface
import com.training.mapper.StudentMapper; // Import StudentMapper for student count update
import org.springframework.beans.factory.annotation.Autowired; // Import Autowired annotation
import org.springframework.stereotype.Service; // Import Service annotation
import org.springframework.transaction.annotation.Transactional; // Import Transactional annotation

import java.util.List; // Import List collection
import java.util.ArrayList; // Import ArrayList (potentially needed for mapping)

@Service // Mark this as a Service class, Spring will manage it
public class ClassService {

    @Autowired // Auto-inject ClassMapper instance
    private ClassMapper classMapper;

    @Autowired // Auto-inject ClassStudentMapper instance
    private ClassStudentMapper classStudentMapper; // Inject ClassStudentMapper

    @Autowired // Auto-inject CouClassMapper instance (for getting class course count)
    private CouClassMapper couClassMapper;

    @Autowired // Auto-inject CourseService instance (for getAllCourses)
    private CourseService courseService;

    @Autowired // Auto-inject StudentMapper instance (for student count update in class)
    private StudentMapper studentMapper;


    /**
     * Get all non-logically deleted classes, or search by keyword.
     * --- MODIFIED ---
     * @param keyword Search keyword for class name (can be null or empty)
     * @return List of Class objects
     */
    public List<Class> getAllClasses(String keyword) {
        // --- NEW LOGIC ---
        // Check if the keyword is not null and not empty after trimming whitespace
        if (keyword != null && !keyword.trim().isEmpty()) {
            // If a keyword is provided, call the new search method on the mapper
            return classMapper.searchClasses(keyword);
        } else {
            // Otherwise, call the original method to get all classes
            return classMapper.findAllClasses();
        }
    }

    /**
     * Get a non-logically deleted class by its ID.
     * @param id Class ID
     * @return Class object, null if not found or logically deleted
     */
    public Class getClassById(Long id) {
        return classMapper.findClassById(id);
    }

    /**
     * Save a new class or update an existing one.
     * @param classObj The Class object to save
     * @return true if save/update is successful, false otherwise
     */
    @Transactional // Add transaction management
    public boolean saveClass(Class classObj) {
        int affectedRows;
        if (classObj.getId() == null) {
            // New class
            // Ensure initial counts are 0, not null
            if (classObj.getClassStuNum() == null) {
                classObj.setClassStuNum(0);
            }
            if (classObj.getClassCouNum() == null) {
                classObj.setClassCouNum(0);
            }

            // --- ADDED LINE ---
            // Explicitly set 'deleted' to 0 (not deleted) for new classes
            classObj.setDeleted(0);
            // --- END ADDED LINE ---

            affectedRows = classMapper.insertClass(classObj);
        } else {
            // Existing class
            // When editing, if classCouNum/classStuNum are not sent from the form, they might be null.
            // Retrieve existing class to preserve its counts if not provided by the form.
            Class existingClass = classMapper.findClassById(classObj.getId());
            if (existingClass != null) {
                if (classObj.getClassStuNum() == null) {
                    classObj.setClassStuNum(existingClass.getClassStuNum() != null ? existingClass.getClassStuNum() : 0);
                }
                if (classObj.getClassCouNum() == null) {
                    classObj.setClassCouNum(existingClass.getClassCouNum() != null ? existingClass.getClassCouNum() : 0);
                }
                // Ensure 'deleted' is not accidentally changed during update unless intended
                if (classObj.getDeleted() == null) {
                    classObj.setDeleted(existingClass.getDeleted());
                }
            } else {
                // Should not happen if ID exists, but as a fallback, initialize to 0
                if (classObj.getClassStuNum() == null) {
                    classObj.setClassStuNum(0);
                }
                if (classObj.getClassCouNum() == null) {
                    classObj.setClassCouNum(0);
                }
                // Set deleted to 0 if it's an update but somehow existingClass is null and deleted is null
                if (classObj.getDeleted() == null) {
                    classObj.setDeleted(0);
                }
            }
            affectedRows = classMapper.updateClass(classObj);
        }
        return affectedRows > 0;
    }

    /**
     * Logically delete a class.
     * @param id Class ID to delete
     * @return true if deleted successfully, false otherwise
     */
    @Transactional // Add transaction management
    public boolean deleteClass(Long id) {
        int affectedRows = classMapper.deleteClass(id);
        return affectedRows > 0;
    }

    /**
     * Get all non-logically deleted students for a given class.
     * This method now returns a List of Student objects with full details.
     * @param classId Class ID
     * @return List of Student objects enrolled in the class
     */
    public List<Student> getStudentsByClassId(Long classId) {
        return classStudentMapper.findStudentsByClassId(classId);
    }

    /**
     * Add a student to a class.
     * @param classId Class ID
     * @param studentId Student ID
     * @return true if student is added successfully, false if already in class or other error
     */
    @Transactional // Add transaction management
    public boolean addStudentToClass(Long classId, Long studentId) {
        // 1. Check if an active association already exists
        if (classStudentMapper.countClassStudent(classId, studentId) > 0) {
            return false; // Student is already actively in this class
        }

        // 2. Check if a logically deleted association exists for the same student and class
        ClassStudent deletedClassStudent = classStudentMapper.findLogicDeletedClassStudent(classId, studentId);
        int affectedRows;

        if (deletedClassStudent != null) {
            // If a deleted record exists, reactivate it instead of inserting a new one
            affectedRows = classStudentMapper.reActivateClassStudent(deletedClassStudent.getId());
        } else {
            // If no active or deleted record exists, insert a new one
            ClassStudent classStudent = new ClassStudent();
            classStudent.setClassId(classId);
            classStudent.setStudentId(studentId);
            classStudent.setDeleted(0); // Not deleted
            affectedRows = classStudentMapper.insertClassStudent(classStudent);
        }

        // Update class student count if the operation was successful
        if (affectedRows > 0) {
            Class classObj = classMapper.findClassById(classId);
            if (classObj != null) {
                // Handle null for classStuNum before incrementing
                Integer currentStuNum = classObj.getClassStuNum();
                if (currentStuNum == null) {
                    currentStuNum = 0; // Initialize to 0 if null
                }
                classObj.setClassStuNum(currentStuNum + 1);
                classMapper.updateClass(classObj); // Update the class in the database
            }
        }
        return affectedRows > 0;
    }

    /**
     * Remove a student from a class.
     * @param classId Class ID
     * @param studentId Student ID
     * @return true if student is removed successfully, false otherwise
     */
    @Transactional // Add transaction management
    public boolean removeStudentFromClass(Long classId, Long studentId) {
        int affectedRows = classStudentMapper.deleteClassStudent(classId, studentId);

        // Update class student count
        if (affectedRows > 0) {
            Class classObj = classMapper.findClassById(classId);
            if (classObj != null) {
                // Handle null for classStuNum before decrementing
                Integer currentStuNum = classObj.getClassStuNum();
                if (currentStuNum == null || currentStuNum <= 0) { // Also handle <= 0 to prevent negative
                    currentStuNum = 0;
                } else {
                    currentStuNum--;
                }
                classObj.setClassStuNum(currentStuNum);
                classMapper.updateClass(classObj); // Update the class in the database
            }
        }
        return affectedRows > 0;
    }

    /**
     * Add a course to a class.
     * @param classId Class ID
     * @param couId Course ID
     * @return true if course is added successfully, false if already in class or other error
     */
    @Transactional // Add transaction management
    public boolean addCourseToClass(Long classId, Long couId) {
        // Check if course is already associated with the class
        if (couClassMapper.countCouClass(classId, couId) > 0) {
            return false; // Course already associated
        }

        CouClass couClass = new CouClass();
        couClass.setClassId(classId);
        couClass.setCouId(couId);
        couClass.setDeleted(0); // Not deleted

        int affectedRows = couClassMapper.insertCouClass(couClass);

        // Update course count in class table
        if (affectedRows > 0) {
            Class classObj = classMapper.findClassById(classId);
            if (classObj != null) {
                // Handle null for classCouNum before incrementing
                Integer currentCouNum = classObj.getClassCouNum();
                if (currentCouNum == null) {
                    currentCouNum = 0; // Initialize to 0 if null
                }
                classObj.setClassCouNum(currentCouNum + 1); // This is the line that caused NPE
                classMapper.updateClass(classObj);
            }
        }
        return affectedRows > 0;
    }

    /**
     * Remove a course from a class.
     * @param classId Class ID
     * @param couId Course ID
     * @return true if course is removed successfully, false otherwise
     */
    @Transactional // Add transaction management
    public boolean removeCourseFromClass(Long classId, Long couId) {
        // Logically delete the association in the cou_class table
        int affectedRows = couClassMapper.deleteCouClass(classId, couId);

        // Update course count in class table
        if (affectedRows > 0) {
            Class classObj = classMapper.findClassById(classId);
            if (classObj != null) {
                // Handle null for classCouNum before decrementing
                Integer currentCouNum = classObj.getClassCouNum();
                if (currentCouNum == null || currentCouNum <= 0) { // Also handle <= 0 to prevent negative
                    currentCouNum = 0;
                } else {
                    currentCouNum--;
                }
                classObj.setClassCouNum(currentCouNum);
                classMapper.updateClass(classObj);
            }
        }
        return affectedRows > 0;
    }

    /**
     * Check if a student is enrolled in a specific class.
     * This is a security check to prevent unauthorized access to class-specific content.
     * @param classId Class ID
     * @param stuId Student ID
     * @return true if the student is enrolled in the class, false otherwise
     */
    public boolean isStudentEnrolledInClass(Long classId, Long stuId) {
        // Use the existing countClassStudent method in ClassStudentMapper
        // If count > 0, it means an active association exists
        return classStudentMapper.countClassStudent(classId, stuId) > 0;
    }

    /**
     * Get all non-logically deleted courses associated with a specific class.
     * @param classId Class ID
     * @return List of Course objects associated with the class
     */
    public List<Course> getCoursesByClassId(Long classId) {
        return couClassMapper.findCoursesByClassId(classId);
    }

    // --- DELETED a duplicate method ---
    // public List<Course> getAllCourses()
    // It already exists in CourseService and was causing confusion.
    // The call in manageClassCourses already correctly calls courseService.getAllCourses()
}